///<reference path="../../framework/events/ContextEvent.ts"/>
///<reference path="BaseLifecycleObj.ts"/>
/**
 * Created by PengWei on 2018/7/27.
 */


namespace game {
    import BaseLifecycleObj = mengdao.BaseLifecycleObj;
    import Injector = mengdao.Injector;
    import BindEventData = mengdao.BindEventData;
    import TypeIdentifier = mengdao.TypeIdentifier;
    import Event = egret.Event;

    export class BaseContextObj extends BaseLifecycleObj {
        /** 上下文 */
        protected _context: Context;

        /** 注入器 */
        protected _injector: Injector;

        /** 激活时间内侦听列表 */
        protected _activeListeners: Map<string, BindEventData>;

        /**
         * 设置Context
         * @param {mengdao.Context} context
         */
        public set context(context: Context) {
            this._context = context;
            this._injector = context.injector;
            this._activeListeners = new Map<string, BindEventData>();
        }

        public active(): void {
            super.active();
            this.activeEvents();
        }

        public sleep(): void {
            super.sleep();
            this.inactiveEvents();
        }

        /**
         * 添加事件
         * 若生命周期处于激活状态，直接添加
         * 若生命周期处于其他状态，添加到队列中
         * @param {string} type
         * @param {Function} callback
         * @param callbackObj
         */
        public addContextListener(type: string, callback: Function, callbackObj: any): BindEventData {
            let data: BindEventData = new BindEventData();
            data.type = type;
            data.callback = callback;
            data.callbackObj = callbackObj;
            data.once = false;

            if (!this._activeListeners.has(type)) {
                this._activeListeners.set(type, data);
            } else {
                return;//ask 已经添加过的type不能再处理更多的callBack,也不能改变once属性了
            }

            if (this._lifecycle.isActive) {//pbm 忘记设置appliedToContext,会导致不能remove。建议取消appliedToContext
                this._context.addEventListener(data.type, this.handleNotifications, this);
            }
        }

        public onceContextListener(type: string, callback: Function, callbackObj: any): BindEventData {
            let data = this.addContextListener(type, callback, callbackObj);
            if (data) {
                data.once = true;
            }
            return data;
        }


        public removeContextListener(type: string): void {
            let data: BindEventData = this._activeListeners.get(type);
            if (data) {
                if (data.appliedToContext) {
                    this._context.removeEventListener(data.type, this.handleNotifications, this);
                }
                data.dispose();
                this._activeListeners.delete(type);
            }
        }

        private activeEvents(): void {
            this._activeListeners.forEach((data: BindEventData) => {
                if (data.appliedToContext == false) {//ask 不使用这个标记也不会重复注册侦听
                    data.appliedToContext = true;
                    this._context.addEventListener(data.type, this.handleNotifications, this);
                }
            }, this);
        }

        private inactiveEvents(): void {
            this._activeListeners.forEach((data: BindEventData) => {
                if (data.appliedToContext == true) {
                    data.appliedToContext = false;
                    this._context.removeEventListener(data.type, this.handleNotifications, this);
                }
            }, this);
        }

        protected handleNotifications(e: Event): void {
            let type = e.type;
            let data: BindEventData = this._activeListeners.get(type);
            if (data) {
                data.callback.call(data.callbackObj,e);
                if (data.once) {
                    this.removeContextListener(type);
                }
            }
        }

        /**
         * EventDispatcher 事件转接
         * dispatcheEvent
         * @param event
         */
        public dispatchEvent(event: Event): boolean {
            return this._context.dispatchEvent(event);
        }


        /**
         * EventDispatcher 事件转接
         * dispatchEventWith
         * @param type
         * @param bubble
         * @param data
         * @param cancelable
         */
        public dispatchEventWith(type: string, data?: any, bubble ?: boolean, cancelable ?: boolean): boolean {
            return this._context.dispatchEventWith(type, bubble, data, cancelable);
        }

        protected get<T>(type: TypeIdentifier<T>): T {
            return this._injector.getFromBind(type);
        }
    }
}